package com.zhou.spring.cloud.balancer.feign.config;

import com.alibaba.csb.sdk.ContentBody;
import com.alibaba.csb.sdk.HttpCaller;
import com.alibaba.csb.sdk.HttpParameters;
import com.alibaba.csb.sdk.HttpReturn;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.wnameless.json.flattener.JsonFlattener;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.zhou.spring.cloud.balancer.util.AESUtil;
import feign.Client;
import feign.QueryMapEncoder;
import feign.Request;
import feign.Response;
import lombok.Setter;
import lombok.SneakyThrows;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;

import java.io.IOException;
import java.net.URLDecoder;
import java.nio.charset.Charset;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

@EnableConfigurationProperties(value = {CsbClientProperties.class})
public class ProvincialPlatformConfiguration {

    @Autowired
    private CsbClientProperties csbClientProperties;

    @Autowired
    private ObjectMapper objectMapper;

    //client 不能设置，会被替代的
/*    @Bean
    public FeignBuilderCustomizer feignBuilderCustomizer() {
        return new FeignBuilderCustomizer() {
            @Override
            public void customize(Feign.Builder builder) {
                builder.client();
            }
        };
    }*/

    @Bean
    public QueryMapEncoder queryMapEncoder() {
        return new QueryMapEncoder() {
            @SneakyThrows
            @Override
            public Map<String, Object> encode(Object object) {
                return JsonFlattener.flattenAsMap(objectMapper.writeValueAsString(object));
            }
        };
    }

    @Bean
    public CsbClient csbClient() {
        return new CsbClient(csbClientProperties.getYdCsbUrl(), csbClientProperties.getAccessKey(),
                csbClientProperties.getSecretKey(), csbClientProperties.getAesPass());
    }

    public static class CsbClient implements Client {

        @Setter
        private String ydCsbUrl;
        private String accessKey;
        private String secretKey;
        private String aesPass;

        public CsbClient(String ydCsbUrl, String accessKey, String secretKey, String aesPass) {
            this.ydCsbUrl = ydCsbUrl;
            this.accessKey = accessKey;
            this.secretKey = secretKey;
            this.aesPass = aesPass;
        }

        HttpParameters.Builder getBuilder() {
            HttpParameters.Builder builder = HttpParameters.newBuilder();
            builder.requestURL(ydCsbUrl) // 设置请求的URL
                    .version("1.0.0") // 设置版本号
                    .method("post")
                    .contentType("application/json")
                    //设置请求content-type
                    .accessKey(accessKey)
                    .secretKey(secretKey);
            return builder;
        }

        @SneakyThrows
        @Override
        public Response execute(Request request, Request.Options options) throws IOException {
            HttpParameters.Builder builder = getBuilder();
            String url = request.url();
            url = URLDecoder.decode(url, "utf-8");
            Map<String, String> paramMap = toMap(url.substring(url.indexOf("?") + 1));
            if (paramMap != null) {
                builder.putParamsMapAll(paramMap);
            }
            Request.HttpMethod httpMethod = request.httpMethod();
            if (httpMethod.equals(Request.HttpMethod.GET)) {
                builder.method("get");
            } else if (httpMethod.equals(Request.HttpMethod.POST)) {
                builder.method("post");
            }
            Map<String, Collection<String>> headers = request.headers();
            if (headers.containsKey("content-type")) {
                for (String value : headers.get("content-type")) {
                    builder.contentType(value);
                }
            }
            String accept = "";
            if (headers.containsKey("Accept")) {
                for (String value : headers.get("Accept")) {
                    accept = value;
                }
            }

            Collection<String> method = headers.get("method");
            for (String value : method) {
                builder.api(value);
            }
            headers.forEach((t, b) -> {
                if (!t.equalsIgnoreCase("content-length")) {
                    builder.putHeaderParamsMap(t, b.iterator().next());
                }
            });


            if (request.body() != null) {
                builder.contentBody(new ContentBody(new String(request.body())));
            }
            HttpReturn httpReturn = HttpCaller.invokeReturn(builder.build());

            int status = httpReturn.httpCode;

            Map<String, Collection<String>> responseHeaders = Maps.newHashMap();
            Map<String, String> headerMap = httpReturn.getHeaderMap();
            for (Map.Entry<String, String> entry : headerMap.entrySet()) {
                responseHeaders.put(entry.getKey(), Lists.newArrayList(entry.getValue()));
            }
            if (StringUtils.isNotEmpty(accept)) {
                responseHeaders.put("Content-Type", Lists.newArrayList(accept));
            }
            String responseStr = httpReturn.response;
            if (accept.contains("json")) {
                if (!responseStr.contains("{")) {
                    responseStr = AESUtil.decrypt(responseStr, aesPass);
                }
            }


            return Response.builder()
                    .status(status)
                    .headers(responseHeaders)
                    .request(request)
                    .body(responseStr, Charset.defaultCharset())
                    .build();
        }
    }

    public static Map<String, String> toMap(String url) {
        Map<String, String> map = null;
        if (url != null && url.indexOf("=") > -1) {
            map = new HashMap<String, String>();
            String[] arrTemp = url.split("&");
            for (String str : arrTemp) {
                String[] qs = str.split("=");
                String name = str.substring(0, str.indexOf("="));
                String value = "";
                if (str.indexOf("=") < str.length()) {
                    value = str.substring(str.indexOf("=") + 1);
                }
                map.put(name, value);
            }
        }
        return map;
    }

}
